﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.IO;
using System.Web;

namespace AppEntity
{
    public partial class Common
    {
        public class XmlTransform
        {
            public string InputXmlFile { get; set; }
            public string InputXmlString { get; set; }
            /// <summary>
            /// InputXmlNode 可以是 XmlDocument, XmlNode, XPathDocument
            /// </summary>
            public IXPathNavigable InputXmlNode { get; set; }

            public string InputXsltXmlFile { get; set; }
            public string InputXsltCode { get; set; }
            public XslCompiledTransform InputXslt { get; set; }
            public Hashtable Argus { get; set; }

            public byte[] TransformToBytes()
            {
                return TransformToStream().ToArray();
            }
            public string TransformToString()
            {
                MemoryStream ms = TransformToStream();
                StreamReader reader = new StreamReader(ms, Encoding.UTF8);
                string html = reader.ReadToEnd();
                reader.Close();
                ms.Close();
                return html;
            }
            public MemoryStream TransformToStream()
            {
                MemoryStream ms = new MemoryStream();
                TransformToStream(ms);
                ms.Position = 0;
                return ms;
                //XslCompiledTransform Xct = GetInputXsltFromCache(this.InputXslt, this.InputXsltXmlFile);
                //XsltArgumentList Arguments = InitArgusList(this.Argus);
                //MemoryStream ms = new MemoryStream();
                //IXPathNavigable Xml = GetInputXml(this.InputXmlNode, this.InputXmlString, this.InputXmlFile);
                //if (Xml == null) return null;
                //Xct.Transform(Xml, Arguments, ms);            
                //ms.Position = 0;            
                //return ms;
            }

            public void TransformToStream(Stream Stream)
            {
                XslCompiledTransform Xct = GetInputXsltFromCache(this.InputXslt, this.InputXsltXmlFile, this.InputXsltCode);
                XsltArgumentList Arguments = InitArgusList(this.Argus);
                //MemoryStream ms = new MemoryStream();
                IXPathNavigable Xml = GetInputXml(this.InputXmlNode, this.InputXmlString, this.InputXmlFile);
                if (Xml == null) return;
                Xct.Transform(Xml, Arguments, Stream);
            }

            private static XsltArgumentList InitArgusList(Hashtable Argus)
            {
                if (Argus == null) return null;
                XsltArgumentList Arguments = new XsltArgumentList();
                foreach (string key in Argus.Keys)
                {
                    if (key.StartsWith("urn:"))
                    {
                        Arguments.AddExtensionObject(key, Argus[key]);
                    }
                    else
                    {
                        Arguments.AddParam(key, String.Empty, Argus[key]);
                    }
                }
                return Arguments;
            }
            private static XslCompiledTransform GetInputXsltFromCache(XslCompiledTransform InputXslt, string InputXsltXmlFile, string InputXsltCode)
            {
                if (InputXslt != null) return InputXslt;
                if (!string.IsNullOrEmpty(InputXsltXmlFile))
                {
                    return GetXslProcessInMemory(InputXsltXmlFile);
                }
                return GetXslProcessInMemoryFromXsltCode(InputXsltCode);
            }
            private static IXPathNavigable GetInputXml(IXPathNavigable InputXmlNode, string InputXmlString, string InputXmlFile)
            {
                if (InputXmlNode != null)
                {
                    return InputXmlNode;
                }
                if (!string.IsNullOrEmpty(InputXmlString))
                {
                    TextReader tr = new StringReader(InputXmlString);
                    XPathDocument xdom = new XPathDocument(tr);
                    tr.Close();
                    return xdom;
                }
                if (!string.IsNullOrEmpty(InputXmlFile) && File.Exists(InputXmlFile))
                {
                    XPathDocument xdom = new XPathDocument(InputXmlFile);
                    return xdom;
                }
                return null;
            }
            /// <summary>
            /// 从 HttpRuntime.Cache 中获取已编译的 Xslt 样式缓存。
            /// </summary>
            /// <param name="XsltFile">Xslt 文件的完整路径，也作为 HttpRuntime.Cache 集合中的键。</param>
            /// <returns></returns>
            public static XslCompiledTransform GetXslProcessInMemory(string XsltFile)
            {
                if (HttpRuntime.Cache[XsltFile] != null)
                {
                    return (XslCompiledTransform)HttpRuntime.Cache[XsltFile];
                }
                XmlReaderSettings Setting = new XmlReaderSettings();
                Setting.ProhibitDtd = false;
                Setting.XmlResolver = new XmlUrlResolver();
                Setting.IgnoreComments = true;
                Setting.IgnoreWhitespace = true;

                XslCompiledTransform Xct = new XslCompiledTransform();
                XsltSettings xs = new XsltSettings(true, true);
                XmlUrlResolver resolver = new XmlUrlResolver();
                resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;

                using (XmlReader Xr = XmlReader.Create(XsltFile, Setting))
                {
                    Xct.Load(Xr, xs, resolver);
                    System.Web.Caching.CacheDependency Dep = new System.Web.Caching.CacheDependency(XsltFile);
                    HttpRuntime.Cache.Insert(XsltFile, Xct, Dep, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), System.Web.Caching.CacheItemPriority.AboveNormal, null);
                    return Xct;
                }

            }
            public static XslCompiledTransform GetXslProcessInMemoryFromXsltCode(string InputXsltCode)
            {
                string CacheKey = "XsltCode-" + InputXsltCode.MD5();
                if (HttpRuntime.Cache[CacheKey] != null)
                {
                    return (XslCompiledTransform)HttpRuntime.Cache[CacheKey];
                }

                XmlReaderSettings Setting = new XmlReaderSettings();
                Setting.ProhibitDtd = false;
                Setting.XmlResolver = new XmlUrlResolver();
                Setting.IgnoreComments = true;
                Setting.IgnoreWhitespace = true;

                XslCompiledTransform Xct = new XslCompiledTransform();
                XsltSettings xs = new XsltSettings(true, true);
                XmlUrlResolver resolver = new XmlUrlResolver();
                resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;

                using (XmlReader Xr = XmlReader.Create(new StringReader(InputXsltCode), Setting))
                {
                    Xct.Load(Xr, xs, resolver);
                    HttpRuntime.Cache.Insert(CacheKey, Xct, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10), System.Web.Caching.CacheItemPriority.AboveNormal, null);
                    return Xct;
                }
            }
            //public static XmlElement CreateSystemElement(XmlDocument Dom)
            //{
            //    XmlElement System = Dom.CreateElement("system");

            //    XmlWriterSettings Setting = new XmlWriterSettings();
            //    Setting.Encoding = Encoding.UTF8;
            //    Setting.OmitXmlDeclaration = true;

            //    StringBuilder sb = new StringBuilder();
            //    XmlWriter Writer = XmlWriter.Create(sb, Setting);            

            //    Writer.WriteStartElement("url");            
            //    foreach (string key in HttpContext.Current.Request.QueryString)
            //    {
            //        if (!string.IsNullOrEmpty(key) && "0123456789".IndexOf(key[0]) < 0 )//xml的属性名不能用数字开头
            //        {
            //            Writer.WriteAttributeString(key, HttpContext.Current.Request.QueryString[key]);                    
            //        }
            //    }
            //    Writer.WriteEndElement();
            //    Writer.Close();

            //    StringBuilder sb2 = new StringBuilder();
            //    XmlWriter Writer2 = XmlWriter.Create(sb2, Setting);
            //    Writer2.WriteStartElement("http");
            //    Writer2.WriteStartElement("cookies");
            //    foreach (string key in HttpContext.Current.Request.Cookies.AllKeys)
            //    {
            //        if (!string.IsNullOrEmpty(key) && "0123456789".IndexOf(key[0]) <0 )
            //        {
            //            string val = HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.Cookies[key].Value);
            //            Writer2.WriteAttributeString(key, val);                    
            //        }
            //    }
            //    Writer2.WriteEndElement();
            //    Writer2.WriteStartElement("variable");
            //    if (HttpContext.Current.Request.UserLanguages != null)
            //    {
            //        Writer2.WriteAttributeString("lang", string.Join(",", HttpContext.Current.Request.UserLanguages));
            //    }
            //    Writer2.WriteAttributeString("servertime", SBS.Common.Utility.GetNowTime());
            //    Writer2.WriteEndElement();
            //    Writer2.WriteEndElement();
            //    Writer2.Close();
            //    sb.Append(sb2.ToString());
            //    System.InnerXml = sb.ToString();
            //    return System;            
            //}
            public static string Transform(XPathNavigator InputXml, string InputXsltFile, Hashtable Argus)
            {
                XmlTransform Xt = new XmlTransform();
                Xt.InputXmlNode = InputXml;
                Xt.InputXsltXmlFile = InputXsltFile;
                Xt.Argus = Argus;
                return Xt.TransformToString();
            }
            public static string Transform(XPathNavigator InputXml, string InputXsltFile)
            {
                return Transform(InputXml, InputXsltFile, null);
            }
            public static string Transform(string InputXml, string InputXsltFile, Hashtable Argus)
            {
                XPathDocument xdom;
                string XmlString = InputXml.Trim();
                if (XmlString.StartsWith("<") && XmlString.EndsWith(">"))
                {
                    TextReader tr = new StringReader(XmlString);
                    xdom = new XPathDocument(tr);
                    tr.Close();
                }
                else
                {
                    xdom = new XPathDocument(InputXml);
                }
                return Transform(xdom.CreateNavigator(), InputXsltFile, Argus);
            }
            public static string Transform(string InputXml, string InputXsltFile)
            {
                return Transform(InputXml, InputXsltFile, null);
            }
        }
    }
}
